﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using Microsoft.SharePoint;
using TSOL.FastSPWeb.ValueObjects;
using TSOL.FastSPWeb.Core;

namespace TSOL.FastSPWeb
{
    public static partial class FastSPWebCallExtensions
    {
        public static void FastSPQueryGetItems(this SPList List, SPQuery Query, 
                                               CachePolicy cachePolicy, 
                                            Action<SPListItemCollection> outProc)
        {
            if (cachePolicy == CachePolicy.FastSPDefault)
            {
                Guid SiteGuid = List.ParentWeb.Site.ID;
                Guid WebGuid = List.ParentWeb.ID;
                SPUser CurrentSPUser = List.ParentWeb.CurrentUser;

                int hashKey = (SiteGuid.ToString() + WebGuid.ToString() + List.ID.ToString() + Query.RowLimit.ToString() + Query.Query.GetHashCode().ToString() + true.ToString() + CurrentSPUser.ID.ToString()).GetHashCode();

                SPQueryCacheCollection _SPQueryCacheCollection = null;
                SPQueryCacheEntity _QueryCache = null;

                while (_QueryCache == null)
                {
                    while (!FastSPWebThreadWorkerQueue.GlobalSPWebThreadWorkerQueue.QueryCacheDictionary.TryGetValue(hashKey, out _SPQueryCacheCollection))
                    {
                        _SPQueryCacheCollection = new SPQueryCacheCollection()
                        {
                            UserUniqueID = CurrentSPUser.ID.ToString(),
                            SiteGuid = SiteGuid,
                            WebGuid = WebGuid,
                            ListGuid = List.ID,
                            Query = Query,
                            MaxCopiesOfElevatedItems = List.ParentWeb.Site.SystemAccount.UserToken.CompareUser(CurrentSPUser.UserToken) ?
                                                FastSPWebThreadWorkerQueue.GlobalSPWebThreadWorkerQueue.MaxCopiesOfElevatedItems :
                                                -1
                        };
                        FastSPQueryFactoryThread.FastSPQueryFactoryThreadTask(List, CurrentSPUser.UserToken, hashKey, _SPQueryCacheCollection);
                    }

                    if (_SPQueryCacheCollection.Count() == 0) FastSPQueryFactoryThread.FastSPQueryFactoryThreadTask(List, CurrentSPUser.UserToken, hashKey, _SPQueryCacheCollection);

                    _QueryCache = _SPQueryCacheCollection.FirstOrDefault(a => a.Free == true);
                    if (_QueryCache != default(SPQueryCacheEntity))
                        break;
                    else
                    {
                        lock (_SPQueryCacheCollection) _SPQueryCacheCollection.WaitingForFreeItems++;
                        FastSPWebThreadWorkerQueue.GlobalSPWebThreadWorkerQueue.FastSPQueryWaitingForFreeCacheEntity++;
                    }
                }
                lock (_QueryCache)
                {
                    try
                    {
                        _QueryCache.Free = false;
                        outProc(_QueryCache.Items);
                        _QueryCache.LastUsed = DateTime.Now;
                    }
                    catch
                    {
                        throw;
                    }
                    finally { 
                        _QueryCache.Free = true;
                    }
                }
            }
            else
            {
                outProc(List.GetItems(Query));
            }
        }
    }
}